package library.net.retrofit.util;

import android.content.res.Resources;
import android.net.Uri;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import library.common.util.FileUtils;
import library.net.retrofit.RxContextType;
import library.net.retrofit.callback.IRxCallback;
import library.net.retrofit.request.RxProgressRequestBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;

/**
 * copy  Copyright (C) 2007 The Guava Authors by from retrofit2
 *
 * @author Tamic(https : / / github.com / NeglectedByBoss)
 */
public class RxUtils {

    /**
     * check if the object is null
     *
     * @param object  check object
     * @param message message about null
     * @param <T>     type
     * @return T
     */
    public static <T> T checkNotNull(T object, String message) {
        if (object == null) {
            throw new NullPointerException(message);
        }
        return object;
    }

    /**
     * check if current thread is main thread
     *
     * @return boolean
     */
    public static boolean checkMain() {
        return Thread.currentThread() == Looper.getMainLooper().getThread();
    }

    /**
     * create RequestBody from string
     *
     * @param content content
     * @return RequestBody
     */
    public static RequestBody createRequestBody(String content, String mediaType) {
        checkNotNull(content, "content not null!");
        if (TextUtils.isEmpty(mediaType)) {
            throw new NullPointerException("contentType not be null");
        } else {
            return RequestBody.create(MediaType.parse(mediaType), content);
        }
    }

    /**
     * create RequestBody from string
     *
     * @param content content
     * @param type    see {@link RxContextType.ContentType}
     * @return RequestBody
     */
    public static RequestBody createRequestBody(String content, RxContextType.ContentType type) {
        checkNotNull(content, "content not null!");
        if (null == type) {
            return RequestBody.create(MediaType.parse(RxContextType.TEXT_DATA), content);
        } else {
            return createRequestBody(content, RxContextType.typeToString(type));
        }
    }

    /**
     * create RequestBody from file
     *
     * @param file      file
     * @param mediaType file type
     * @return RequestBody
     */
    @NonNull
    public static RequestBody createRequestBody(File file, String mediaType) {
        checkNotNull(file, "file not be null!");
        if (TextUtils.isEmpty(mediaType)) {
            throw new NullPointerException("contentType not be null");
        }
        return RequestBody.create(MediaType.parse(mediaType), file);
    }

    /**
     * create RequestBody from file
     *
     * @param file file
     * @param type see {@link RxContextType.ContentType}
     * @return RequestBody
     */
    @NonNull
    public static RequestBody createRequestBody(File file, RxContextType.ContentType type) {
        checkNotNull(file, "file not be null!");
        checkNotNull(type, "contentType not be null!");
        return createRequestBody(file, RxContextType.typeToString(type));
    }

    /**
     * create RxProgressRequestBody from String
     *
     * @param content  content
     * @param type     see {@link RxContextType.ContentType}
     * @param callback IRxCallback
     * @return RxProgressRequestBody
     */
    @NonNull
    public static RxProgressRequestBody createRxRequestBody(@NonNull String content, @NonNull RxContextType.ContentType type, IRxCallback callback) {
        return new RxProgressRequestBody(createRequestBody(content, type), callback);
    }

    /**
     * create RxProgressRequestBody from file
     *
     * @param file     file
     * @param type     see {@link RxContextType.ContentType}
     * @param callback IRxCallback
     * @return RxProgressRequestBody
     */
    @NonNull
    public static RxProgressRequestBody createRxRequestBody(@NonNull File file, @NonNull RxContextType.ContentType type, IRxCallback callback) {
        return new RxProgressRequestBody(createRequestBody(file, type), callback);
    }

    /**
     * create MultipartBody.Part from file
     *
     * @param partName part name
     * @param file     file
     * @param type     file type
     * @return MultipartBody.Part
     */
    @NonNull
    public static MultipartBody.Part createPart(String partName, File file, RxContextType.ContentType type) {
        if (null == type) {
            // create RequestBody instance from file
            type = RxContextType.ContentType.FORM;
        }
        RequestBody requestFile = createRequestBody(file, type);
        // MultipartBody.Part is used to send also the actual file name
        return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
    }

    /**
     * create MultipartBody.Part from file uri
     *
     * @param partName part name
     * @param fileUri  file uri
     * @return MultipartBody.Part
     */
    @NonNull
    public static MultipartBody.Part createPart(String partName, Uri fileUri) {
        // use the FileUtils to get the actual file by uri
        File file = FileUtils.getUirFile(fileUri);
        // create RequestBody instance from file
        RequestBody requestFile = createRequestBody(file, RxContextType.ContentType.FORM);
        // MultipartBody.Part is used to send also the actual file name
        return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
    }

    /**
     * create MultipartBody from files
     *
     * @param partName part name
     * @param fileMap  Files
     * @param type     ContentType type
     * @param callback ResponseCallback
     * @return MultipartBody
     */
    @NonNull
    public static MultipartBody createMultipartBody(String partName,
                                                    Map<String, File> fileMap, @NonNull RxContextType.ContentType type, IRxCallback callback) {
        MultipartBody.Builder builder = new MultipartBody.Builder();
        if (fileMap != null && fileMap.size() > 0) {
            RxProgressRequestBody requestBody = null;
            for (Map.Entry entry : fileMap.entrySet()) {
                File file = (File) entry.getValue();
                if (null == file) {
                    throw new Resources.NotFoundException("file is null");
                } else if (!file.exists()) {
                    throw new Resources.NotFoundException(file.getPath() + "file 路径无法找到");
                } else {
                    requestBody = createRxRequestBody(file, type, callback);
                    // MultipartBody.Part is used to send also the actual file name
                    builder.addFormDataPart(partName, file.getName(), requestBody);
                }
            }
        }
        return builder.build();
    }


    /**
     * create MultipartBody Parts from files
     *
     * @param partName part name
     * @param fileMap  Files
     * @param type     ContentType type
     * @param callback ResponseCallback
     * @return Map<MultipartBody.Part> <key, part>
     */
    @NonNull
    public static Map<String, MultipartBody.Part> createParts(String partName,
                                                              Map<String, File> fileMap, @NonNull RxContextType.ContentType type, IRxCallback callback) {
        // create RequestBody instance from file
        Map<String, MultipartBody.Part> parts = new HashMap<>();
        if (fileMap != null && fileMap.size() > 0) {
            RxProgressRequestBody requestBody = null;
            for (Map.Entry entry : fileMap.entrySet()) {
                File file = (File) entry.getValue();
                if (null == file) {
                    throw new Resources.NotFoundException("file is null");
                } else if (!file.exists()) {
                    throw new Resources.NotFoundException(file.getPath() + "file 路径无法找到");
                } else {
                    requestBody = createRxRequestBody(file, type, callback);
                    // MultipartBody.Part is used to send also the actual file name
                    MultipartBody.Part body =
                            MultipartBody.Part.createFormData(partName, file.getName(), requestBody);
                    parts.put((String) entry.getKey(), body);
                }
            }
        }
        return parts;
    }

    /**
     * create MultipartBody Parts
     *
     * @param partName part name
     * @param list     List<File>
     * @param type     ContentType type
     * @param callback ResponseCallback
     * @return List<MultipartBody.Part>
     */
    @NonNull
    public static List<MultipartBody.Part> createPart(String partName,
                                                      List<File> list, @NonNull RxContextType.ContentType type, IRxCallback callback) {
        List<MultipartBody.Part> parts = new ArrayList<>();
        if (list != null && list.size() > 0) {
            RxProgressRequestBody requestBody = null;
            for (File file : list) {
                if (!file.exists()) {
                    throw new Resources.NotFoundException(file.getPath() + "file 路径无法找到");
                } else {
                    requestBody = createRxRequestBody(file, type, callback);
                    // MultipartBody.Part is used to send also the actual file name
                    MultipartBody.Part body =
                            MultipartBody.Part.createFormData(partName, file.getName(), requestBody);
                    parts.add(body);
                }
            }
        }
        return parts;
    }


    /**
     * create RxProgressRequestBody
     *
     * @param requestBody requestBody
     * @param callback    ResponseCallback
     * @return RxProgressRequestBody
     */
    @NonNull
    public static RxProgressRequestBody createProgressRequestBody(RequestBody requestBody, IRxCallback callback) {
        return new RxProgressRequestBody(requestBody, callback);
    }
}
